# 
import argparse
from typing import Dict
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

class Chp01Sec04S3(object):
    def __init__(self):
        self.name = ''

    @staticmethod
    def startup(params:Dict = {}) -> None:
        print(f'Linear Regression 3 Demo v0.0.1')
        # Chp01Sec04S3.naive_method()
        Chp01Sec04S3.professional_method()

    @staticmethod
    def naive_method() -> None:
        plt.rcParams['figure.figsize'] = [16, 8]
        plt.rcParams.update({'font.size': 18})
        # Load dataset
        H = np.loadtxt('study/ddse/supports/DATA_PYTHON/DATA/housing.data')
        b = H[:,-1] # housing values in $1000s
        A = H[:,:-1] # other factors
        # Pad with ones for nonzero offset
        A = np.pad(A,[(0,0),(0,1)],mode='constant',constant_values=1)
        # Solve Ax=b using SVD
        # Note that the book uses the Matlab-specific "regress" command
        U, S, VT = np.linalg.svd(A,full_matrices=0)
        x = VT.T @ np.linalg.inv(np.diag(S)) @ U.T @ b
        fig = plt.figure()
        ax1 = fig.add_subplot(121)
        plt.plot(b, color='k', linewidth=2, label='Housing Value') # True relationship
        plt.plot(A@x, '-o', color='r', linewidth=1.5, markersize=6, label='Regression')
        plt.xlabel('Neighborhood')
        plt.ylabel('Median Home Value [$1k]')
        plt.legend()
        ax2 = fig.add_subplot(122)
        sort_ind = np.argsort(H[:,-1])
        b = b[sort_ind] # sorted values
        plt.plot(b, color='k', linewidth=2, label='Housing Value') # True relationship
        plt.plot(A[sort_ind,:]@x, '-o', color='r', linewidth=1.5, markersize=6, label='Regression')
        plt.xlabel('Neighborhood')
        plt.legend()
        plt.show()
        # 确定特征的重要性
        A_mean = np.mean(A,axis=0)
        A_mean = A_mean.reshape(-1, 1)
        A2 = A - np.ones((A.shape[0],1)) @ A_mean.T
        for j in range(A.shape[1]-1):
            A2std = np.std(A2[:,j])
            A2[:,j] = A2[:,j]/A2std
        A2[:,-1] = np.ones(A.shape[0])
        U, S, VT = np.linalg.svd(A2,full_matrices=0)
        x = VT.T @ np.linalg.inv(np.diag(S)) @ U.T @ b
        x_tick = range(len(x)-1)+np.ones(len(x)-1)
        plt.bar(x_tick,x[:-1])
        plt.xlabel('Attribute')
        plt.ylabel('Significance')
        plt.xticks(x_tick)
        plt.show()

    @staticmethod
    def professional_method() -> None:
        plt.rcParams['figure.figsize'] = [16, 8]
        plt.rcParams.update({'font.size': 18})
        # Load dataset
        H = np.loadtxt('study/ddse/supports/DATA_PYTHON/DATA/housing.data')
        b = H[:,-1] # housing values in $1000s
        A = H[:,:-1] # other factors
        # Pad with ones for nonzero offset
        A = np.pad(A,[(0,0),(0,1)],mode='constant',constant_values=1)
        m = 506 # 样本总数
        train_test_split = 0.8
        train_num = int(m*train_test_split)
        p = np.random.permutation(m)
        A = A[p, :]
        b = b[p]
        A_train = A[1:train_num]
        b_train = b[1:train_num]
        A_test = A[train_num:]
        b_test = b[train_num:]
        # Solve Ax=b using SVD
        # Note that the book uses the Matlab-specific "regress" command
        U, S, VT = np.linalg.svd(A_train,full_matrices=0)
        x = VT.T @ np.linalg.inv(np.diag(S)) @ U.T @ b_train
        fig = plt.figure()
        ax1 = fig.add_subplot(121)
        plt.plot(b_train, color='k', linewidth=2, label='Housing Value') # True relationship
        plt.plot(A_train@x, '-o', color='r', linewidth=1.5, markersize=6, label='Regression')
        plt.xlabel('Neighborhood')
        plt.ylabel('Median Home Value [$1k]')
        plt.legend()
        plt.title('performance in training set')
        ax2 = fig.add_subplot(122)
        plt.plot(b_test, color='k', linewidth=2, label='Housing Value') # True relationship
        plt.plot(A_test@x, '-o', color='r', linewidth=1.5, markersize=6, label='Regression')
        plt.xlabel('Neighborhood')
        plt.ylabel('Median Home Value [$1k]')
        plt.legend()
        plt.title('performance in test set')
        plt.show()

def main(params:Dict = {}) -> None:
    Chp01Sec04S3.startup(params=params)

def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--run_mode', action='store',
        type=int, default=1, dest='run_mode',
        help='run mode'
    )
    return parser.parse_args()

if '__main__' == __name__:
    args = parse_args()
    params = vars(args)
    main(params=params)